bitkeeper revision 1.394 (3f3f5bd5J74WkH-WgWI6a5W5aobvaQ)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Sun, 17 Aug 2003 10:41:25 +0000 (10:41 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Sun, 17 Aug 2003 10:41:25 +0000 (10:41 +0000)
Many files:
  Forced TLB flushes when a domain page changes type is now done more lazily. Fixed a few bugs at the same time, and cleaned up perfctr output.

xen/arch/i386/boot/boot.S
xen/arch/i386/mm.c
xen/arch/i386/smp.c
xen/arch/i386/traps.c
xen/common/dom_mem_ops.c
xen/common/domain_page.c
xen/common/memory.c
xen/common/perfc.c
xen/drivers/block/xen_block.c
xen/include/asm-i386/pgalloc.h
xen/include/xeno/perfc_defn.h

index 36078037d442b273091de975f7e6d1dbffa67002..3068e46899116dc97a3d88ecb62c5e6c35130edc 100644 (file)
@@ -14,13 +14,9 @@ ENTRY(start)
         /* Magic number indicating a Multiboot header. */
        .long   0x1BADB002
        /* Flags to bootloader (see Multiboot spec). */
-       .long   0x00000006
+       .long   0x00000002
        /* Checksum: must be the negated sum of the first two fields. */
-       .long   -0x1BADB008
-        /* Unused loader addresses (ELF header has all this already).*/
-        .long   0,0,0,0,0
-        /* EGA text mode. */
-        .long   1,0,0,0
+       .long   -0x1BADB004
         
 hal_entry:
         /* Set up a few descriptors: on entry only CS is guaranteed good. */
index 7bccd34f9c086e578f12eab4fa043706e5aa1299..b32650c614f6d57e8830b37b78f7dd7295c146ff 100644 (file)
@@ -241,13 +241,13 @@ long do_set_gdt(unsigned long *frame_list, unsigned int entries)
             mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
         
         page = frame_table + frames[i];
-        page->flags &= ~PG_type_mask;
+        page->flags &= ~(PG_type_mask | PG_need_flush);
         page->flags |= PGT_gdt_page;
         get_page_type(page);
         get_page_tot(page);
     }
 
-    flush_tlb();
+    local_flush_tlb();
 
     /* Copy over first entries of the new GDT. */
     memcpy((void *)GDT_VIRT_START, gdt_table, FIRST_DOMAIN_GDT_ENTRY*8);
index c049ed0e502bfb040f997261480863d1b527eb29..3cae3ec1d8428e9194e275e2c5e91f83e54f48c8 100644 (file)
@@ -352,48 +352,6 @@ void flush_tlb_others(unsigned long cpumask)
     spin_unlock(&tlbstate_lock);
 }
        
-void flush_tlb_current_task(void)
-{
-#if 0
-    struct mm_struct *mm = &current->mm;
-    unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id());
-
-    local_flush_tlb();
-    if (cpu_mask)
-        flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
-#endif
-}
-
-void flush_tlb_mm (struct mm_struct * mm)
-{
-#if 0
-    unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id());
-
-    if (current->active_mm == mm)
-        local_flush_tlb();
-    if (cpu_mask)
-        flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
-#endif
-}
-
-#if 0
-void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
-{
-    struct mm_struct *mm = vma->vm_mm;
-    unsigned long cpu_mask = mm.cpu_vm_mask & ~(1 << smp_processor_id());
-
-    if (current->active_mm == mm) {
-        if(current->mm)
-            __flush_tlb_one(va);
-        else
-            leave_mm(smp_processor_id());
-    }
-
-    if (cpu_mask)
-        flush_tlb_others(cpu_mask, mm, va);
-}
-#endif
-
 static inline void do_flush_tlb_all_local(void)
 {
     unsigned long cpu = smp_processor_id();
index 119641767e3b961ed3d743b879277a8eb961b275..5109d01af2fd068936741b411f64e661ae360c1d 100644 (file)
@@ -18,6 +18,7 @@
 #include <xeno/delay.h>
 #include <xeno/spinlock.h>
 #include <xeno/irq.h>
+#include <xeno/perfc.h>
 #include <asm/domain_page.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -323,6 +324,13 @@ asmlinkage void do_page_fault(struct pt_regs *regs, long error_code)
                 goto unlock_and_bounce_fault;
         unmap_domain_mem(ldt_page);
 
+        if ( page->flags & PG_need_flush )
+        {
+            perfc_incrc(need_flush_tlb_flush);
+            local_flush_tlb();
+            page->flags &= ~PG_need_flush;
+        }
+
         page->flags &= ~PG_type_mask;
         page->flags |= PGT_ldt_page;
     }
index 0dd7111ac815b048ed381482fe79bd0585c9661f..d1691dda7da1d5917ca6104e24394db176e0a40e 100644 (file)
@@ -11,6 +11,7 @@
 #include <xeno/lib.h>
 #include <xeno/mm.h>
 #include <xeno/dom_mem_ops.h>
+#include <xeno/perfc.h>
 #include <xeno/sched.h>
 #include <xeno/event.h>
 #include <asm/domain_page.h>
@@ -89,6 +90,7 @@ static long free_dom_mem(struct task_struct *p, balloon_inf_op_t bop)
     unsigned long     i;
     unsigned long     flags;
     long              rc = 0;
+    int               need_flush = 0;
 
     spin_lock_irqsave(&free_list_lock, flags);
     spin_lock(&p->page_lock);
@@ -117,6 +119,8 @@ static long free_dom_mem(struct task_struct *p, balloon_inf_op_t bop)
             goto out;
         }
 
+        need_flush |= pf->flags & PG_need_flush;
+
         pf->flags = 0;
 
         list_del(&pf->list);
@@ -130,6 +134,12 @@ static long free_dom_mem(struct task_struct *p, balloon_inf_op_t bop)
     spin_unlock(&p->page_lock);
     spin_unlock_irqrestore(&free_list_lock, flags);
     
+    if ( need_flush )
+    {
+        __flush_tlb();
+        perfc_incrc(need_flush_tlb_flush);
+    }
+
     return rc ? rc : bop.size;
 }
     
index 9257aa728a3dc18aff9331cd98e88147c9b3dbb0..0e90fb45cbf279f3a6a078b26316d65c0ccf4f77 100644 (file)
@@ -31,7 +31,7 @@ static void flush_all_ready_maps(void)
     do { if ( (*cache & READY_FOR_TLB_FLUSH) ) *cache = 0; }
     while ( ((unsigned long)(++cache) & ~PAGE_MASK) != 0 );
 
-    perfc_incr(domain_page_tlb_flush);
+    perfc_incrc(domain_page_tlb_flush);
     local_flush_tlb();
 }
 
index 1d58472c9fa577e19e15988096c0e6ec634d2ee4..ee94d9654208466cb02ca9e95462b38873e33876 100644 (file)
@@ -70,7 +70,6 @@
 
 /*
  * THE FOLLOWING ARE ISSUES IF GUEST OPERATING SYSTEMS BECOME SMP-CAPABLE.
- * [THAT IS, THEY'RE NOT A PROBLEM NOW, AND MAY NOT EVER BE.]
  * -----------------------------------------------------------------------
  * 
  * *********
@@ -83,7 +82,6 @@
  * than one, we'd probably just flush on all processors running the domain.
  * *********
  * 
- * ** 1 **
  * The problem involves creating new page tables which might be mapped 
  * writeable in the TLB of another processor. As an example, a domain might be 
  * running in two contexts (ie. on two processors) simultaneously, using the 
  * FLUSH_NONE, FLUSH_PAGETABLE, FLUSH_DOMAIN. A flush reduces this
  * to FLUSH_NONE, while squashed write mappings can only promote up
  * to more aggressive flush types.
- * 
- * ** 2 **
- * Same problem occurs when removing a page table, at level 1 say, then
- * making it writeable. Need a TLB flush between otherwise another processor
- * might write an illegal mapping into the old table, while yet another
- * processor can use the illegal mapping because of a stale level-2 TLB
- * entry. So, removal of a table reference sets 'flush_level' appropriately,
- * and a flush occurs on next addition of a fresh write mapping.
- * 
- * BETTER SOLUTION FOR BOTH 1 AND 2:
- * When type_refcnt goes to zero, leave old type in place (don't set to
- * PGT_none). Then, only flush if making a page table of a page with
- * (cnt=0,type=PGT_writeable), or when adding a write mapping for a page
- * with (cnt=0, type=PGT_pagexxx). A TLB flush will cause all pages
- * with refcnt==0 to be reset to PGT_none. Need an array for the purpose,
- * added to when a type_refcnt goes to zero, and emptied on a TLB flush.
- * Either have per-domain table, or force TLB flush at end of each
- * call to 'process_page_updates'.
- * Most OSes will always keep a writeable reference hanging around, and
- * page table structure is fairly static, so this mechanism should be
- * fairly cheap.
- * 
- * MAYBE EVEN BETTER? [somewhat dubious: not for first cut of the code]:
- * If we need to force an intermediate flush, those other processors
- * spin until we complete, then do a single TLB flush. They can spin on
- * the lock protecting 'process_page_updates', and continue when that
- * is freed. Saves cost of setting up and servicing an IPI: later
- * communication is synchronous. Processors trying to install the domain
- * or domain&pagetable would also enter the spin.
- * 
- * ** 3 **
- * Indeed, this problem generalises to reusing page tables at different
- * levels of the hierarchy (conceptually, the guest OS can use the
- * hypervisor to introduce illegal table entries by proxy). Consider
- * unlinking a level-1 page table and reintroducing at level 2 with no
- * TLB flush. Hypervisor can add a reference to some other level-1 table
- * with the RW bit set. This is fine in the level-2 context, but some
- * other processor may still be using that table in level-1 context
- * (due to a stale TLB entry). At level 1 it may look like the
- * processor has write access to the other level-1 page table! Therefore
- * can add illegal values there with impunity :-(
- * 
- * Fortunately, the solution above generalises to this extended problem.
  */
 
-/*
- * UPDATE 12.11.02.: We no longer have struct page and mem_map. These
- * have been replaced by struct pfn_info and frame_table respectively.
- * 
- * system_free_list is a list_head linking all system owned free pages.
- * it is initialized in init_frametable.
- *
- * Boris Dragovic.
- */
 #include <xeno/config.h>
 #include <xeno/init.h>
 #include <xeno/lib.h>
 #include <xeno/mm.h>
 #include <xeno/sched.h>
 #include <xeno/errno.h>
+#include <xeno/perfc.h>
 #include <asm/page.h>
 #include <asm/flushtlb.h>
 #include <asm/io.h>
@@ -305,6 +251,13 @@ static int inc_page_refcnt(unsigned long page_nr, unsigned int type)
             return -1;
         }
 
+        if ( flags & PG_need_flush )
+        {
+            flush_tlb[smp_processor_id()] = 1;
+            page->flags &= ~PG_need_flush;
+            perfc_incrc(need_flush_tlb_flush);
+        }
+
         page->flags &= ~PG_type_mask;
         page->flags |= type;
     }
@@ -540,11 +493,7 @@ static void put_page(unsigned long page_nr, int writeable)
             ((page->flags & PG_need_flush) == PG_need_flush)));
     if ( writeable )
     {
-        if ( put_page_type(page) == 0 )
-        {
-            flush_tlb[smp_processor_id()] = 1;
-            page->flags &= ~PG_need_flush;
-        }
+        put_page_type(page);
     }
     else if ( unlikely(((page->flags & PG_type_mask) == PGT_ldt_page) &&
                        (page_type_count(page) != 0)) )
index 00f599e8819c9e2d71827b87c688991ea3d3cbeb..00d0505503006b485df7e68e9d24ba2b46cc8191 100644 (file)
@@ -25,7 +25,7 @@ struct perfcounter_t perfcounters;
 
 void perfc_printall(u_char key, void *dev_id, struct pt_regs *regs)
 {
-    int i, j;
+    int i, j, sum;
     s_time_t now = NOW();
     atomic_t *counters = (atomic_t *)&perfcounters;
 
@@ -34,27 +34,27 @@ void perfc_printall(u_char key, void *dev_id, struct pt_regs *regs)
 
     for ( i = 0; i < NR_PERFCTRS; i++ ) 
     {
-        printk("%20s  ",  perfc_info[i].name);
+        printk("%-32s  ",  perfc_info[i].name);
         switch ( perfc_info[i].type )
         {
         case TYPE_SINGLE:
-            printk("%10d  0x%08x",
-                   atomic_read(&counters[0]), 
-                   atomic_read(&counters[0]));
+            printk("TOTAL[%10d]", atomic_read(&counters[0]));
             counters += 1;
             break;
         case TYPE_CPU:
+            for ( j = sum = 0; j < smp_num_cpus; j++ )
+                sum += atomic_read(&counters[j]);
+            printk("TOTAL[%10d]  ", sum);
             for ( j = 0; j < smp_num_cpus; j++ )
-                printk("CPU%02d[%10d 0x%08x]  ",
-                       j, atomic_read(&counters[j]), 
-                       atomic_read(&counters[j]));
+                printk("CPU%02d[%10d]  ", j, atomic_read(&counters[j]));
             counters += NR_CPUS;
             break;
         case TYPE_ARRAY:
+            for ( j = sum = 0; j < perfc_info[i].nr_elements; j++ )
+                sum += atomic_read(&counters[j]);
+            printk("TOTAL[%10d]  ", sum);
             for ( j = 0; j < perfc_info[i].nr_elements; j++ )
-                printk("ARR%02d[%10d 0x%08x]  ",
-                       j, atomic_read(&counters[j]), 
-                       atomic_read(&counters[j]));
+                printk("ARR%02d[%10d]  ", j, atomic_read(&counters[j]));
             counters += j;
             break;
         }
index 3ef15116dfb8b3ab82baf7ff45d7e9a5b907bb76..3a56144007e075215f8b7a224b415d36ff5143f9 100644 (file)
@@ -316,8 +316,8 @@ static void __lock_buffer(unsigned long buffer,
         {
             if ( page->type_count == 0 )
             {
-                page->flags &= ~(PG_type_mask | PG_need_flush);
-                /* NB. This ref alone won't cause a TLB flush. */
+                page->flags &= ~PG_type_mask;
+                /* No need for PG_need_flush here. */
                 page->flags |= PGT_writeable_page;
             }
             get_page_type(page);
@@ -340,13 +340,8 @@ static void unlock_buffer(struct task_struct *p,
           pfn++ )
     {
         page = frame_table + pfn;
-        if ( writeable_buffer &&
-             (put_page_type(page) == 0) &&
-             (page->flags & PG_need_flush) )
-        {
-            __flush_tlb();
-            page->flags &= ~PG_need_flush;
-        }
+        if ( writeable_buffer )
+            put_page_type(page);
         put_page_tot(page);
     }
     spin_unlock_irqrestore(&p->page_lock, flags);
index ed5f9cdb16ecb630882fbbce2bf521cb57daaa93..7ccf9c1da9cfae3d796265a6bbc72209e6c3f93d 100644 (file)
@@ -39,9 +39,6 @@
  *
  *  - flush_tlb() flushes the current mm struct TLBs
  *  - flush_tlb_all() flushes all processes TLBs
- *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
- *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  *
  * ..but the i386 has somewhat limited tlb flushing capabilities,
 
 #ifndef CONFIG_SMP
 
-#define flush_tlb() __flush_tlb()
-#define flush_tlb_all() __flush_tlb_all()
-#define local_flush_tlb() __flush_tlb()
-
-static inline void flush_tlb_mm(struct mm_struct *mm)
-{
-       if (mm == current->active_mm)
-               __flush_tlb();
-}
-
-static inline void flush_tlb_cpu(unsigned int cpu)
-{
-    __flush_tlb();
-}
-
-#if 0
-static inline void flush_tlb_page(struct vm_area_struct *vma,
-       unsigned long addr)
-{
-       if (vma->vm_mm == current->active_mm)
-               __flush_tlb_one(addr);
-}
-#endif
-
-static inline void flush_tlb_range(struct mm_struct *mm,
-       unsigned long start, unsigned long end)
-{
-       if (mm == current->active_mm)
-               __flush_tlb();
-}
+#define flush_tlb()         __flush_tlb()
+#define flush_tlb_all()     __flush_tlb_all()
+#define local_flush_tlb()   __flush_tlb()
+#define flush_tlb_cpu(_cpu) __flush_tlb()
 
 #else
 
 #include <xeno/smp.h>
 
-#define local_flush_tlb() \
-       __flush_tlb()
+#define flush_tlb()        __flush_tlb()
+#define local_flush_tlb()   __flush_tlb()
 
 extern void flush_tlb_all(void);
-extern void flush_tlb_current_task(void);
-extern void flush_tlb_mm(struct mm_struct *);
-
-#define flush_tlb()    flush_tlb_current_task()
-
-static inline void flush_tlb_range(struct mm_struct * mm, unsigned long start, unsigned long end)
-{
-       flush_tlb_mm(mm);
-}
 
 extern void flush_tlb_others(unsigned long cpumask);
 static inline void flush_tlb_cpu(unsigned int cpu)
index 2c53e8334d259c6a5e3819f78e10152804c63043..891be997867dad9120061d706774bc772217723b 100644 (file)
@@ -16,4 +16,5 @@ PERFCOUNTER( net_rx_delivered, "net rx delivered" )
 PERFCOUNTER( net_rx_tlbflush, "net rx tlb flushes" )
 PERFCOUNTER( net_tx_transmitted, "net tx transmitted" )
 
-PERFCOUNTER( domain_page_tlb_flush, "domain page tlb flushes" )
+PERFCOUNTER_CPU( domain_page_tlb_flush, "domain page tlb flushes" )
+PERFCOUNTER_CPU( need_flush_tlb_flush, "PG_need_flush tlb flushes" )